package com.zeyu.soc.log.utils;

import java.util.List;
import java.util.Map;

import org.eclipse.jetty.util.StringUtil;

import com.zeyu.soc.log.WebServer;
import com.zeyu.soc.log.provider.ClassWrapper;
import com.zeyu.soc.log.provider.FieldWrapper;

/**
 * 界面渲染公用类
 */
public class ViewUtils {

	// ================================================================
	// Constants
	// ================================================================

	// ================================================================
	// Fields
	// ================================================================

	// ================================================================
	// Constructors
	// ================================================================

	// ================================================================
	// Methods from/for super Interfaces or SuperClass
	// ================================================================

	// ================================================================
	// Public or Protected Methods
	// ================================================================

	/**
	 * 首页界面
	 * @param rewrite 
	 */
	public static String renderIndex(List<Map<String, String>> wrappers, String rewrite) {
		
		if (StringUtil.isBlank(rewrite)){
			rewrite = "";
		} else {
			rewrite = "/" + rewrite;
		}
		
		// 渲染模板
		StringBuffer buffer = new StringBuffer("");
		buffer.append("<div>");
		buffer.append("    <div class=\"bs-callout bs-callout-warning\">");
		buffer.append("        <h3>本机所有<code>Java</code>虚拟机列表</h3>");
		buffer.append("        <p class=\"bs-log-nav\"> 可以选择<code>添加注入</code>或者<code>查看、移除注入</code>即可操作.</p>");
		buffer.append("    </div>");
		buffer.append("    <table class=\"table table-bordered table-striped table-hover\">");
		buffer.append("        <thead>");
		buffer.append("            <tr>");
		buffer.append("                <th class=\"bs-log-th-no\">#</th>");
		buffer.append("                <th class=\"bs-log-th-id\">Java进程<code>Id</code></th>");
		buffer.append("                <th class=\"bs-log-th\">执行路径</th>");
		buffer.append("                <th class=\"bs-log-th-ctl\">操作</th>");
		buffer.append("            </tr>");
		buffer.append("         </thead>");
		buffer.append("         <tbody>");
		// 加入JVM
		if (wrappers != null && wrappers.size() > 0) {
			for (int i = 0; i < wrappers.size(); i++) {
				Map<String, String> wrapper = wrappers.get(i);
				buffer.append("            <tr>");
				buffer.append("                <th scope=\"row\">" + (i + 1) + "</th>");
				buffer.append("                <td>" + wrapper.get("id") + "</td>");
				if (wrapper.get("displayName").length() > 90) {
					buffer.append("                <td>" + wrapper.get("displayName").substring(0, 90) + "</td>");
				} else {
					buffer.append("                <td>" + wrapper.get("displayName") + "</td>");
				}

				buffer.append("                <td>");
				buffer.append("                    <a href=\""+rewrite+"/control/" + wrapper.get("id")
						+ "\" class=\"btn btn-primary\" role=\"button\">");
				buffer.append("                        <span class=\"glyphicon glyphicon-import\" aria-hidden=\"true\"></span> 添加注入");
				buffer.append("                    </a>");
				if ("true".equalsIgnoreCase(wrapper.get("connected").toString())) {
					buffer.append("                    <a href=\""+rewrite+"/injectionDescriptor/" + wrapper.get("id")
							+ "\" class=\"btn btn-primary btn-info\" role=\"button\">");
					buffer.append("                        <span class=\"glyphicon glyphicon-eye-open\" aria-hidden=\"true\"></span> 查看注入");
					buffer.append("                    </a>");
					buffer.append("                    <a href=\""+rewrite+"/clear/" + wrapper.get("id")
							+ "\" class=\"btn btn-primary btn-success\" role=\"button\">");
					buffer.append("                        <span class=\"glyphicon glyphicon-export\" aria-hidden=\"true\"></span> 清除修改");
					buffer.append("                    </a>");
				}
				buffer.append("                </td>");
				buffer.append("            </tr>");
			}
		}

		buffer.append("        </tbody>");
		buffer.append("    </table>");
		buffer.append("    <div class=\"bs-log-div\">");
		buffer.append("    </div>");
		buffer.append("</div>");

		return renderBasic("虚拟机列表", buffer.toString(), rewrite);
	}

	/**
	 * 帮助界面
	 * @param rewrite 
	 */
	public static String renderHelp(String rewrite) {
		
		if (StringUtil.isBlank(rewrite)){
			rewrite = "";
		} else {
			rewrite = "/" + rewrite;
		}

		// 渲染模板
		StringBuffer buffer = new StringBuffer("");

		buffer.append("<div>");
		buffer.append("    <h2>日志注入</h2>");
		buffer.append("    <p><code>日志注入</code> 是一个可以在代码的任意区域无入侵地加入日志的工具，适用于线上问题排查.</p>");
		buffer.append("    <p><code>日志注入</code> 为开发人员提供一个易于使用的平台，帮助开发人员在正在运行的系统中随时加入自己想要的日志，而免于修改代码和重启.</p>");
		buffer.append("    <div class=\"bs-callout bs-callout-warning margin-top\">");
		buffer.append("        <h4>使用场景举例</h4>");
		buffer.append("        <p> 1、一些同学在写代码时，把异常吃掉了，使得问题难以查找，可以使用这个工具，动态打印出被吃掉的异常，而不用停机.</p>");
		buffer.append("        <p> 2、一些项目依赖第三方jar包，如果发生问题，但第三方包中无日志打印，以往可能需要重新编译第");
		buffer.append("                        三方包，加上日志，重启服务，然后排查问题。但使用这个工具，就可以直接动态加入日志，而不用修改第三方jar包，也不用重启.");
		buffer.append("        </p>");
		buffer.append("    </div>");
		buffer.append("    <div class=\"bs-callout bs-callout-warning margin-top\">");
		buffer.append("        <h4>已有功能</h4>");
		buffer.append("        <p> 1、让系统打印某个<code>exception</code>的堆栈，无论此<code>exception</code>是否已经被吃掉都可打印.</p>");
		buffer.append("        <p> 2、在某个指定类的某个方法的某一行，输出日志.</p>");
		buffer.append("        <p> 3、在某个指定类的某个方法的开始，输出日志.</p>");
		buffer.append("        <p> 4、在某个指定类的某个方法的结束，输出日志.</p>");
		buffer.append("        <p> 5、打印方法耗时，支持方法嵌套.</p>");
		buffer.append("        <p> 如果需要扩展新的功能（例如输出jvm的cpu占用，内存大小等），只需要实现<code>spi</code>中的");
		buffer.append("             <code>com.zeyu.framework.log.spi.TransformDescriptor</code>");
		buffer.append("             和<code>com.zeyu.framework.log.spi.TransformHandler</code>接口，");
		buffer.append("             然后把实现的jar包放到<code>providers</code>目录中即可识别.</p>");
		buffer.append("    </div>");
		buffer.append("    <div class=\"bs-callout bs-callout-warning margin-top\">");
		buffer.append("        <h4>使用方法</h4>");
		buffer.append("        <p> 1、直接执行<code>startup.bat</code>或者<code>startup.sh</code>即可运行起来.</p>");
		buffer.append("        <p> 2、访问 <code>http://127.0.0.1:4567</code> 即可使用.</p>");
		buffer.append("    </div>");
		buffer.append("    <div class=\"bs-callout bs-callout-warning margin-top\">");
		buffer.append("        <h4>功能扩展</h4>");
		buffer.append("        <p><code>日志注入</code>利用<code>spi</code>机制实现其扩展，如果你想要对<code>日志注入</code>增加新的功能（例如添加返回值打印的功能）可以按照如下步骤操作</p>");
		buffer.append("        <p> 1、在IDE中创建一个<code>spi</code>实现工程.</p>");
		buffer.append("        <p> 2、参照该工程中已有的两个例子（一个是在方法开始插入日志，一个是在方法结束插入日志），实现<code>TransformDescriptor</code>和<code>TransformHandler</code>接口.");
		buffer.append("        </p>");
		buffer.append("        <p> 3、把两个接口实现类的全路径，分别加到以下两个文件中");
		buffer.append("               <code>src/main/resources/META-INF/services/com.zeyu.framework.log.spi.TransformDescriptor</code> 和 ");
		buffer.append("               <code>src/main/resources/META-INF/services/com.zeyu.framework.log.spi.TransformHandler</code>.");
		buffer.append("        </p>");
		buffer.append("        <p> 4、把扩展实现jar拷贝到<code>日志注入</code>的<code>providers</code>目录下，重启即可生效.");
		buffer.append("        </p>");
		buffer.append("    </div>");
		buffer.append("    <div class=\"bs-log-div\">");
		buffer.append("    </div>");
		buffer.append("</div>");

		return renderBasic("帮助", buffer.toString(), rewrite);
	}

	/**
	 * 操作界面
	 * @param rewrite 
	 */
	@SuppressWarnings("unchecked")
	public static String renderOperator(Map<String, Object> wrapper, String rewrite) {
		
		if (StringUtil.isBlank(rewrite)){
			rewrite = "";
		} else {
			rewrite = "/" + rewrite;
		}
		
		// 渲染模板
		StringBuffer buffer = new StringBuffer("");
		buffer.append("<div>");
		buffer.append("    <div class=\"bs-callout bs-callout-warning\">");
		buffer.append("        <h3 class=\"text-info\">操作参数设置</h3>");
		buffer.append("        <p class=\"bs-log-nav\"> 根据表单设置操作参数,可以使用下面的內置函数列表.</p>");
		buffer.append("        <p></p>");
		buffer.append("        <h3 class=\"text-info\">內置函数列表</h3>");
		buffer.append("        <p> 1、<code>$sysout -> System.out.println</code>: 用于将日志打到本身<code>JVM</code>的标准输出.</p>");
		buffer.append("        <p> 2、<code>$trace -> com.zeyu.soc.log.tools.Trace.trace</code>: 用于将日志打印到本工具logs目录的<code>{pid}.log</code>文件.</p>");
		buffer.append("        <p> 3、<code>$json -> com.zeyu.soc.log.utils.JsonUtils.toJson</code>: 用于对象转<code>json</code>.</p>");
		buffer.append("    </div>");
		buffer.append("    <div class=\"panel-body highlight\">");
		buffer.append("        <h2 class=\"text-info\">参数设置:</h2>");
		buffer.append("        <form class=\"form-horizontal\" role=\"form\" action=\""+rewrite+"/dooperator\" method=\"post\">");
		buffer.append("            <input type=\"hidden\" name=\"pid\" value=\"" + wrapper.get("pid") + "\"/>");
		buffer.append("            <input type=\"hidden\" name=\"operateClassName\" value=\""
				+ wrapper.get("operateClassName") + "\"/>");

		List<FieldWrapper> fieldWrappers = ((List<FieldWrapper>) wrapper.get("fields"));
		for (FieldWrapper fieldWrapper : fieldWrappers) {
			String fieldKey = fieldWrapper.getFieldName();
			buffer.append("        <div class=\"form-group\">");
			buffer.append("            <label for=\"" + fieldKey + "\" class=\"col-sm-2 control-label\">" + fieldKey
					+ "</label>");
			buffer.append("            <div class=\"col-sm-10\">");
			buffer.append("                <input type=\"text\" class=\"form-control\" id=\"" + fieldKey + "\" name=\""
					+ fieldKey + "\"");
			buffer.append("                placeholder=\"" + htmEncode(fieldWrapper.getFieldDesc()) + "\" />");
			buffer.append("            </div>");
			buffer.append("        </div>");
		}

		buffer.append("            <div class=\"form-group\">");
		buffer.append("                <div class=\"col-sm-offset-2 col-sm-10\">");
		buffer.append("                <button type=\"submit\" class=\"btn btn-primary\">");
		buffer.append("                    <span class=\"glyphicon glyphicon-hand-right\" aria-hidden=\"true\"></span> 提交");
		buffer.append("                </button>");
		buffer.append("            </div>");
		buffer.append("        </form>");
		buffer.append("    </div>");

		buffer.append("    <div class=\"bs-log-div\">");
		buffer.append("    </div>");
		buffer.append("</div>");

		return renderBasic("操作(注入)结果", buffer.toString(), rewrite);
	}

	/**
	 * 操作选择界面
	 * @param rewrite 
	 */
	public static String renderControl(List<Map<String, String>> wrappers, String rewrite) {
		
		if (StringUtil.isBlank(rewrite)){
			rewrite = "";
		} else {
			rewrite = "/" + rewrite;
		}
		
		// 渲染模板
		StringBuffer buffer = new StringBuffer("");
		buffer.append("<div>");
		buffer.append("   <div class=\"bs-callout bs-callout-warning\">");
		buffer.append("       <h3>对选择的<code>Java</code>进程进行注入</h3>");
		buffer.append("       <p class=\"bs-log-nav\"> 如果需要扩展新的功能（例如输出<code>JVM</code>的<code>CPU</code>占用，内存大小等）,请查看帮助.</p>");
		buffer.append("   </div>");
		buffer.append("   <table class=\"table table-bordered table-striped table-hover\">");
		buffer.append("       <thead>");
		buffer.append("           <tr>");
		buffer.append("               <th class=\"bs-log-th-no\">#</th>");
		buffer.append("               <th class=\"bs-log-th-cls\">注入操作类</th>");
		buffer.append("               <th class=\"bs-log-th\">注入操作描述</th>");
		buffer.append("               <th class=\"bs-log-th-ctl\">操作</th>");
		buffer.append("           </tr>");
		buffer.append("       </thead>");
		buffer.append("       <tbody>");

		// 加入操作
		if (wrappers != null && wrappers.size() > 0) {
			for (int i = 0; i < wrappers.size(); i++) {
				Map<String, String> wrapper = wrappers.get(i);
				buffer.append("           <tr>");
				buffer.append("               <th scope=\"row\">" + (i + 1) + "</th>");
				buffer.append("               <td class=\"text-warning\">" + wrapper.get("className") + "</td>");
				buffer.append("               <td>" + wrapper.get("classDesc") + "</td>");
				buffer.append("               <td>");
				buffer.append("                   <a href=\""+rewrite+"/operator/" + wrapper.get("id") + /*"?operate="*/"--"
						+ wrapper.get("className") + "\" class=\"btn btn-success\" role=\"button\">");
				buffer.append("                       <span class=\"glyphicon glyphicon-plus-sign\" aria-hidden=\"true\"></span> 注入");
				buffer.append("                   </a>");
				buffer.append("               </td>");
				buffer.append("            </tr>");
			}
		}

		buffer.append("        </tbody>");
		buffer.append("    </table>");
		buffer.append("    <div class=\"bs-log-div\">");
		buffer.append("    </div>");
		buffer.append("</div>");

		return renderBasic("操作选择", buffer.toString(), rewrite);
	}

	/**
	 * 注入结果界面
	 * @param rewrite 
	 */
	public static String renderInjectionResult(Map<String, Object> wrapper, String rewrite) {
		
		if (StringUtil.isBlank(rewrite)){
			rewrite = "";
		} else {
			rewrite = "/" + rewrite;
		}
		
		// 渲染模板
		StringBuffer buffer = new StringBuffer("");
		buffer.append("<div>");
		buffer.append("    <div class=\"bs-callout bs-callout-warning\">");
		buffer.append("        <h3>操作(注入)结果</h3>");
		buffer.append("    </div>");
		buffer.append("    <div class=\"panel-body\">");
		// 加入结果
		if (wrapper != null && wrapper.size() > 0) {
			if ("true".equalsIgnoreCase(wrapper.get("result").toString())) {
				buffer.append("        <h2 class=\"text-info\">注入成功:</h2>");
				buffer.append("        <form class=\"form-horizontal\">");
				buffer.append("            <div class=\"form-group highlight\">");
				buffer.append("                <h3 class=\"text-warning\">" + wrapper.get("className") + "</h3>");

				ClassWrapper fields = ((ClassWrapper) wrapper.get("fields"));
				for (FieldWrapper field : fields.getFieldWrappers()) {
					String fieldKey = field.getFieldName();
					buffer.append("                <label for=\"" + fieldKey + "\" class=\"col-sm-2 control-label\">"
							+ fieldKey + "</label>");
					buffer.append("                <div class=\"col-sm-10\">");
					buffer.append("                    <input type=\"text\" class=\"form-control\" id=\"" + fieldKey
							+ "\" name=\"" + fieldKey + "\"");
					buffer.append("                           placeholder=\"" + htmEncode(field.getValue())
							+ "\" disabled=\"disabled\"/>");
					buffer.append("                </div>");
				}

				buffer.append("            </div>");
				buffer.append("        </form>");
			} else {
				buffer.append("        <h2 class=\"text-info\">注入失败:</h2>");
				buffer.append("        <form class=\"form-horizontal\">");
				buffer.append("            <div class=\"form-group highlight\">");
				buffer.append("                <h3 class=\"text-warning\">" + wrapper.get("className") + "</h3>");
				buffer.append("                错误信息：" + wrapper.get("message"));
				buffer.append("            </div>");
				buffer.append("        </form>");
			}
		}

		buffer.append("    </div>");
		buffer.append("    <div class=\"bs-log-div\">");
		buffer.append("    </div>");
		buffer.append("</div>");

		return renderBasic("操作(注入)结果", buffer.toString(), rewrite);
	}

	/**
	 * 注入列表展示界面
	 * @param rewrite 
	 */
	public static String renderInjectionDescriptor(List<ClassWrapper> wrappers, String rewrite) {
		
		if (StringUtil.isBlank(rewrite)){
			rewrite = "";
		} else {
			rewrite = "/" + rewrite;
		}
		
		// 渲染模板
		StringBuffer buffer = new StringBuffer("");
		buffer.append("<div>");
		buffer.append("    <div class=\"bs-callout bs-callout-warning\">");
		buffer.append("        <h3><code>JVM</code>已经注入列表</h3>");
		buffer.append("        <p class=\"bs-log-nav\"> 可以查看<code>JVM</code>中已经注入的操作列表,不可修改.</p>");
		buffer.append("    </div>");
		buffer.append("    <div class=\"panel-body\">");
		// 加入结果
		if (wrappers != null && wrappers.size() > 0) {
			for (ClassWrapper wrapper : wrappers) {
				buffer.append("        <form class=\"form-horizontal\">");
				buffer.append("            <div class=\"form-group highlight\">");
				buffer.append("                <h3 class=\"text-warning\">" + wrapper.getClassName() + "("
						+ wrapper.getClassDesc() + ")" + "</h3>");

				List<FieldWrapper> fields = wrapper.getFieldWrappers();
				for (FieldWrapper field : fields) {
					String fieldKey = field.getFieldName();
					buffer.append("                <label for=\"" + fieldKey + "\" class=\"col-sm-2 control-label\">"
							+ fieldKey + "</label>");
					buffer.append("                <div class=\"col-sm-10\">");
					buffer.append("                    <input type=\"text\" class=\"form-control\" id=\"" + fieldKey
							+ "\" name=\"" + fieldKey + "\"");
					buffer.append("                           placeholder=\"" + htmEncode(field.getValue())
							+ "\" disabled=\"disabled\"/>");
					buffer.append("                </div>");
				}

				buffer.append("            </div>");
				buffer.append("        </form>");
			}
		}

		buffer.append("    </div>");
		buffer.append("    <div class=\"bs-log-div\">");
		buffer.append("    </div>");
		buffer.append("</div>");

		return renderBasic("注入列表", buffer.toString(), rewrite);
	}

	/**
	 * 把文本编码为Html代码
	 */
	public static String htmEncode(Object target) {
		StringBuffer stringbuffer = new StringBuffer();
		if (target == null) {
			return "";
		}
		int j = target.toString().length();
		for (int i = 0; i < j; i++) {
			char c = target.toString().charAt(i);
			switch (c) {
			case 60:
				stringbuffer.append("&lt;");
				break;
			case 62:
				stringbuffer.append("&gt;");
				break;
			case 38:
				stringbuffer.append("&amp;");
				break;
			case 34:
				stringbuffer.append("&quot;");
				break;
			case 169:
				stringbuffer.append("&copy;");
				break;
			case 174:
				stringbuffer.append("&reg;");
				break;
			case 165:
				stringbuffer.append("&yen;");
				break;
			case 8364:
				stringbuffer.append("&euro;");
				break;
			case 8482:
				stringbuffer.append("&#153;");
				break;
			case 13:
				if (i < j - 1 && target.toString().charAt(i + 1) == 10) {
					stringbuffer.append("<br>");
					i++;
				}
				break;
			case 32:
				if (i < j - 1 && target.toString().charAt(i + 1) == ' ') {
					stringbuffer.append(" &nbsp;");
					i++;
					break;
				}
			default:
				stringbuffer.append(c);
				break;
			}
		}
		return new String(stringbuffer.toString());
	}

	// ================================================================
	// Getter & Setter
	// ================================================================

	// ================================================================
	// Private Methods
	// ================================================================

	/**
	 * 渲染基础模板首页
	 */
	private static String renderBasic(String title, String html, String rewrite) {
		if (StringUtil.isBlank(rewrite)){
			rewrite = "";
		}
		
		// 渲染模板
		StringBuffer buffer = new StringBuffer("");
		// head
		buffer.append("<!DOCTYPE html>");
		buffer.append("<html>");
		buffer.append("<head>");
		buffer.append("    <meta charset=\"UTF-8\">");
		buffer.append("    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
		buffer.append("    <meta name=\"description\" content=\"日志注入 - 可以随时在不中断系统的情况下加入日志!\">");
		buffer.append("    <title> " + title + " - 日志注入</title>");
		buffer.append("    <link rel=\"icon\" href=\""+rewrite+"/img/favicon.png\">");
		buffer.append("    <link rel=\"stylesheet\" href=\""+rewrite+"/css/bootstrap.min.css\">");
		buffer.append("    <link rel=\"stylesheet\" href=\""+rewrite+"/css/style.css\">");
		buffer.append("</head>");
		// body
		buffer.append("<body>");
		buffer.append("<div class=\"container-fluid\">");
		buffer.append("    <div class=\"row clearfix\">");
		buffer.append("        <div class=\"col-md-12 column\">");
		buffer.append("            <div class=\"page-header\">");
		buffer.append("                <h2 class=\"bs-log-nav\">");
		buffer.append("                    <ul class=\"nav nav-pills\">");
		buffer.append("                        <li><a href=\""+rewrite+"/index\">JVM列表页</a></li>");
		buffer.append("                        <li><a href=\""+rewrite+"/help\">帮助</a></li>");
		buffer.append("                        <li class=\"disabled\"><a href=\"#\" class=\"bs-log-li-text\">本程序不支持IE,建议使用Chrome浏览器</a></li>");
		buffer.append("                   </ul>");
		buffer.append("              </h2>");
		buffer.append("          </div>");
		buffer.append("       </div>");
		buffer.append("    </div>");
		// the html you will insert.
		buffer.append(html);
		// footer
		if (WebServer.inDialog) {
			buffer.append("	    <footer class=\"bs-log-footer hide\">");
		} else {
			buffer.append("	    <footer class=\"bs-log-footer\">");
		}
		buffer.append("         <div><p>可以在代码的任意区域无入侵地加入日志的工具，适用于线上问题排查.</p></div>");
		buffer.append("     </footer>");
		buffer.append("</div>");
		buffer.append("<script src=\""+rewrite+"/js/jquery-2.1.4.min.js\"></script>");
		buffer.append("<script src=\""+rewrite+"/js/bootstrap.min.js\"></script>");
		buffer.append("</body>");
		buffer.append("</html>");

		return buffer.toString();
	}

	// ================================================================
	// Inner or Anonymous Class
	// ================================================================

	// ================================================================
	// Test Methods
	// ================================================================
}
